﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using Newtonsoft.Json;

namespace SPMS.Common
{
    /// <summary>
    /// 扩展模型绑定器。
    /// </summary>
    public class ExtendedModelBinder : DefaultModelBinder
    {
        #region ---Protected Method

        /// <summary>
        /// 使用指定的控制器上下文、绑定上下文、属性描述符和属性联编程序来返回属性值。
        /// </summary>
        /// <param name="controllerContext">运行控制器的上下文。 上下文信息包括控制器、HTTP 内容、请求上下文和路由数据。</param>
        /// <param name="bindingContext">绑定模型的上下文。 上下文包含模型对象、模型名称、模型类型、属性筛选器和值提供程序等信息。</param>
        /// <param name="propertyDescriptor">要访问的属性的描述符。 该描述符提供组件类型、属性类型和属性值等信息。 它还提供用于获取或设置属性值的方法。</param>
        /// <param name="propertyBinder">一个对象，提供用于绑定属性的方式。</param>
        /// <returns>
        /// 一个对象，表示属性值。
        /// </returns>
        protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
        {
            //判断是否包含JSON反序列化特性
            foreach (Attribute attribute in propertyDescriptor.Attributes)
            {
                //判断是否包含JSON反序列化特性
                if (attribute is JsonBinderAttribute)
                {
                    //返回属性值
                    return this.DeserializeProperty(bindingContext, propertyDescriptor);
                }
            }

            //调用基类实现
            return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        }

        #endregion

        #region ---Property

        /// <summary>
        /// 反序列化属性值。
        /// </summary>
        /// <param name="bindingContext">绑定模型的上下文。 上下文包含模型对象、模型名称、模型类型、属性筛选器和值提供程序等信息。</param>
        /// <param name="propertyDescriptor">要访问的属性的描述符。 该描述符提供组件类型、属性类型和属性值等信息。 它还提供用于获取或设置属性值的方法。</param>
        /// <returns>
        /// 一个对象，表示属性值。 
        /// </returns>
        private object DeserializeProperty(ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
        {
            //获得属性结果
            ValueProviderResult result = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);

            //判断序列化器是否已经创建
            if (null == this.m_JsonSerializer)
            {
                //创建转换器
                JsonConverter[] converters = new JsonConverter[]
                {
                    //日期转换器
                    new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter()
                };

                //创建序列化器设置
                JsonSerializerSettings settings = new JsonSerializerSettings()
                {
                    NullValueHandling = NullValueHandling.Ignore,
                    Converters = converters
                };

                //创建序列化器
                this.m_JsonSerializer = JsonSerializer.Create(settings);
            }

            //判断是否包含属性值
            if (null != result.RawValue)
            {
                //创建读取器
                using (JsonTextReader reader = new JsonTextReader(new StringReader(result.AttemptedValue)))
                {
                    //反序列化
                    return this.m_JsonSerializer.Deserialize(reader, propertyDescriptor.PropertyType);
                }
            }

            //默认返回空引用
            return null;
        }

        #endregion

        #region ---Field

        /// <summary>
        /// JSON序列化器
        /// </summary>
        private JsonSerializer m_JsonSerializer;

        #endregion
    }
}
